#include "eeprom.h"
#include "bsp_i2c.h"


#define checkAck(x) do{if(x) return 1;}while(0)

/**
 * @brief eeprom ms delay
 * 
 * @param ms 
 */
static void eepromDelay(uint16_t ms){
    (void) ms;
}

static eepromOps_t eepromStruct = {
    i2cInit,
    i2cStart,
    i2cStop,
    i2cWaitAck,
    i2cWriteByte,
    i2cReadByte,
    eepromDelay,
    AT24C64,
};
static eepromOps_t * eepromOps = NULL;

/**
 * @brief eeprom read one byte
 * 
 * @param readAddr  read date addr
 * @return uint8_t 
 */
uint8_t at24cxxReadOneByte(uint16_t readAddr){
    uint8_t date = 0;
    eepromOps->eepromI2cStart();
    if(eepromOps->eepromType > AT24C16){
        eepromOps->eepromWriteByte(0XA0);	   
		checkAck(eepromOps->eepromWaitAck());
		eepromOps->eepromWriteByte(readAddr >> 8); 
    }else{
        eepromOps->eepromWriteByte(0XA0 + ((readAddr / 256) << 1));
    }
    checkAck(eepromOps->eepromWaitAck());
    eepromOps->eepromWriteByte(readAddr % 256); 
	checkAck(eepromOps->eepromWaitAck());
	eepromOps->eepromI2cStart();
	eepromOps->eepromWriteByte(0XA1);           
	checkAck(eepromOps->eepromWaitAck());
	date = eepromOps->eepromReadByte(0);
	eepromOps->eepromI2cStop();
	return date;
}

/**
 * @brief eeprom write one byte
 * 
 * @param writeAddr  write date addr
 * @param date write date
 * @return uint8_t 
 */
uint8_t at24cxxWriteOneByte(uint16_t writeAddr,uint8_t date){
    eepromOps->eepromI2cStart();
	if(eepromOps->eepromType > AT24C16)
	{
		eepromOps->eepromWriteByte(0XA0);	   
		checkAck(eepromOps->eepromWaitAck());
		eepromOps->eepromWriteByte(writeAddr >> 8); 
	}
	else
	{
		eepromOps->eepromWriteByte(0XA0 + ((writeAddr / 256) << 1)); 
	}
	checkAck(eepromOps->eepromWaitAck());
	eepromOps->eepromWriteByte(writeAddr % 256); 
	checkAck(eepromOps->eepromWaitAck());
	eepromOps->eepromWriteByte(date);    
	checkAck(eepromOps->eepromWaitAck());
	eepromOps->eepromI2cStop();
    if(eepromOps->eepromDelay){
        eepromOps->eepromDelay(10);
    }
    return 0;
}

/**
 * @brief eeprom read len byte
 * 
 * @param readAddr read addr
 * @param len read length
 * @return uint32_t 
 */
uint32_t at24cxxReadLenByte(uint16_t readAddr,uint8_t len){
    uint8_t t;
	uint32_t date = 0;
	for(t = 0; t < len; t++){
		date <<= 8;
		date += at24cxxReadOneByte(readAddr + len - t - 1);
	}
	return date;
}

/**
 * @brief eeprom read date
 * 
 * @param readAddr read date addr
 * @param buffer read buffer
 * @param size read size
 */
void at24cxxRead(uint16_t readAddr,uint8_t *buffer,uint16_t size){
    while(size)
	{
		*buffer++ = at24cxxReadOneByte(readAddr++);
		size --;
	}
}


/**
 * @brief eeprom write len byte date
 * 
 * @param writeAddr write addr
 * @param date write date
 * @param len writ len
 * @warning date must is halfword or word
 */
void at24cxxWriteLenByte(uint16_t writeAddr,uint32_t date,uint8_t len){
    uint8_t t = 0;
	for(t = 0; t < len; t++){
		at24cxxWriteOneByte(writeAddr + t, (date >> (8 * t)) & 0xff);
	}
}

/**
 * @brief eeprom write date
 * 
 * @param writeAddr write addr
 * @param buffer write buffer
 * @param size write size
 */
void at24cxxWrite(uint16_t writeAddr,uint8_t *buffer,uint16_t size){
    while(size--){
		at24cxxWriteOneByte(writeAddr, *buffer);
		writeAddr++;
		buffer++;
	}
}

/**
 * @brief eeprom init
 * 
 */
void at24cxxInit(void){
    eepromOps = &eepromStruct;
    eepromOps->eepromI2cInit();
    uint8_t date = 0x02;
    uint8_t rDate = 0;
    at24cxxWriteOneByte(0,date);
    rDate = at24cxxReadOneByte(0);
    if(rDate == date){
        printf("eeprom read write Success\r\n");
    }else{
        printf("eeprom read write Fail\r\n");
    }    
}